package cn.datawin.common.state.template.condition;

import cn.datawin.common.state.StateMachineUtil;
import cn.datawin.common.state.action.LocalBackAction;
import cn.datawin.common.state.action.StateWindUpAction;
import cn.datawin.common.state.template.BaseTemplate;
import cn.hutool.core.util.StrUtil;
import org.springframework.util.CollectionUtils;
import org.squirrelframework.foundation.fsm.UntypedAnonymousAction;
import org.squirrelframework.foundation.fsm.UntypedStateMachineBuilder;

import java.util.ArrayList;
import java.util.List;

import static cn.datawin.common.state.constant.State.END;


/**
 * 带内部状态机的模板
 * @Author: huanyayun
 * @Date: 2021/10/27 16:00
 */
public class ConditionTemplate extends BaseTemplate {

    /**
     * 内部状态机
     */
    private List<ConditionTemplateDetail> conditionTemplateDetails;

    public List<ConditionTemplateDetail> getConditionTemplateDetails() {
        return conditionTemplateDetails;
    }

    public void setConditionTemplateDetails(List<ConditionTemplateDetail> conditionTemplateDetails) {
        this.conditionTemplateDetails = conditionTemplateDetails;
    }

    public ConditionTemplate(String stateName, List<UntypedAnonymousAction> actions, String entryFunc, String exitFunc, List<ConditionTemplateDetail> conditionTemplateDetails) {
        super(stateName, actions, entryFunc, exitFunc);
        this.conditionTemplateDetails = conditionTemplateDetails;
    }

    @Override
    public void execActions(UntypedStateMachineBuilder builder) {

        //执行进入外部状态stateName的方法
        if(StrUtil.isNotBlank(entryFunc)){
            StateMachineUtil.onEntryCallMethod(stateName,builder,entryFunc);
        }

        if(!CollectionUtils.isEmpty(conditionTemplateDetails)){

            //----->外部stateA----->外部stateB
            //         ↓
            //     满足进入内部A状态的条件，进入内部A，执行对应的操作，再回到外部stateA
            //         ↓
            //     满足进入内部B状态的条件，进入内部B，执行对应的操作，再回到外部stateA
            //         ↓
            //     满足进入内部C状态的条件，进入内部C，执行对应的操作，再回到外部stateA
            //         ↓
            //     满足进入内部D状态的条件，进入内部D，执行对应的操作，再回到外部stateA
            //     ..........
            //         ↓
            //     满足进入内部兜底,回到外部stateA

            for (ConditionTemplateDetail conditionTemplateDetail : conditionTemplateDetails) {

                //定义从stateName=>内部状态中的某一个状态，触发event stateName+"_EXEC"  触发条件 conditionTemplateDetail.getCondition()
                StateMachineUtil.localTransition(stateName, conditionTemplateDetail.getName(),stateName+"_EXEC", conditionTemplateDetail.getCondition(),builder);
                //获取某个内部状态需要执行actions
                List<UntypedAnonymousAction> actionList = conditionTemplateDetail.getActions();
                //在执行的所有actions尾部加上回跳到主链路上stateName状态的action
                actionList.add(new LocalBackAction());
                //定义进入内部状态需要执行的actions
                StateMachineUtil.onEntry(conditionTemplateDetail.getName(),builder,actionList);
                //定义进入内部状态到外部状态stateName的链路
                StateMachineUtil.localTransition(conditionTemplateDetail.getName(),stateName,builder);
            }

            //满足进入内部兜底,回到外部stateA
            LocalBackCondition localBackCondition = new LocalBackCondition(stateName);
            String conditionName = localBackCondition.name();
            StateMachineUtil.localTransition(stateName, conditionName,stateName+"_EXEC",localBackCondition,builder);
            //获取某个内部状态需要执行actions
            List<UntypedAnonymousAction> actionList = new ArrayList<>();
            //在执行的所有actions尾部加上回跳到主链路上stateName状态的action
            actionList.add(new LocalBackAction());
            //定义进入内部状态需要执行的actions
            StateMachineUtil.onEntry(conditionName,builder,actionList);
            //定义进入内部状态到外部状态stateName的链路
            StateMachineUtil.localTransition(conditionName,stateName,builder);

        }
        //进入状态执行参数中actions外加CheckEndAction,检测是否触发完毕
        actions.add(new StateWindUpAction());
        StateMachineUtil.onEntry(stateName,builder,actions);

        //定义状态到end的跳转链路
        StateMachineUtil.external(stateName,END,builder);

        //如果配置了exitFunc，定义离开触发的方法
        if(StrUtil.isNotBlank(exitFunc)){
            StateMachineUtil.onExitCallMethod(stateName,builder,exitFunc);
        }
    }
}
